Skip to content

Feat: Cadastrar, Renomear e Remover tipos de vegetações - #525

Open
JosueModesto wants to merge 5 commits into
developmentfrom
490-cadastrar-renomear-remover-tipos-vegetacoes
Open

JosueModesto wants to merge 5 commits into
developmentfrom
490-cadastrar-renomear-remover-tipos-vegetacoes

Conversation

@JosueModesto

@JosueModesto JosueModesto commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Close #490

O que foi feito

Foi implementado o módulo de cadastro, atualização e remoção de tipos de vegetação na API v2, preservando a API legada sem alterações e seguindo o padrão de autenticação já utilizado pelo projeto.

Alterações principais

  • Implementação dos endpoints de vegetação na API v2:
    • POST /api/v2/vegetacoes
    • PUT /api/v2/vegetacoes/:vegetacaoId
    • DELETE /api/v2/vegetacoes/:vegetacaoId
  • Validação de acesso de escrita com middleware específico para vegetações, respeitando o segredo JWT do projeto e os tipos de usuário permitidos.
  • Validação de nome vazio com retorno 400.
  • Validação de duplicidade de nome com retorno 409.
  • Validação de vegetacaoId inválido com retorno 400.
  • Retorno 404 quando o registro não existe.
  • Tratamento de conflito ao remover uma vegetação em uso em tombos com retorno 409.
  • Garantia de integridade no banco por meio de index único em LOWER(nome), além de tratamento compatível de erros de duplicidade e dependência em diferentes motores de banco.
  • Manutenção da API legacy /api sem alterações.

Cobertura de testes

  • Cadastro com sucesso
  • Cadastro com nome vazio
  • Cadastro com nome duplicado
  • Atualização de vegetação existente
  • Atualização com id inexistente
  • Atualização com id inválido
  • Atualização com nome duplicado
  • Remoção com sucesso
  • Remoção com vegetação em uso
  • Rejeição de token assinado com segredo inválido quando JWT_SECRET não está configurado

@JosueModesto
JosueModesto requested review from edvaldoszy and a lite review from Copilot and removed request for Copilot September 4, 2026 19:37

return [
{
handlers: [

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

POST, PUT e DELETE montam só o controller em handlers. O legado POST /vegetacoes exige tokensMiddleware([CURADOR, OPERADOR]). País/estado v2 são só GET públicos e não justificam mutação anônima do catálogo. Os testes de escrita passam sem Authorization.

Comment thread src/application/vegetacao/CadastraVegetacaoController.ts Outdated
}
})

test('retorna 404 para id inexistente', async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O PR pede nome vazio → 400, duplicidade → 409, vegetacaoId inválido → 400 e 404. Este arquivo só cobre sucesso, 404 e id abc. DELETE só cobre 204 e 409 em uso. No PUT, nome duplicado vira BadRequestError 400, não 409.

Comment thread src/application/vegetacao/RenomeiaVegetacaoController.ts Outdated
return Either.left(new CollectionError({ message: cause.message, cause }))
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unicidade é findByNome e depois insert/update. A tabela vegetacoes só tem PK, então duas requisições concorrentes com o mesmo nome passam no select e as duas gravam. O catch de unique/23505 não dispara sem constraint.

Comment thread test/integration/vegetacao/cadastra-vegetacoes.test.ts Outdated
Comment thread src/application/vegetacao/RequireVegetacaoWriteAccess.ts Outdated
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL
);

CREATE UNIQUE INDEX vegetacoes_nome_unique

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O índice único em LOWER(nome) existe só no schema de integração. Não há migration em src/database e o model Sequelize de vegetacoes.nome não é unique. Em MySQL de produção o check-then-write continua sujeito a corrida e o 23505 do adapter não dispara.

const message = typeof error === 'object' && error !== null && 'message' in error ? String((error as { message?: unknown }).message) : ''
const constraint = typeof error === 'object' && error !== null && 'constraint' in error ? String((error as { constraint?: unknown }).constraint) : ''

return code === '23505'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unique e FK estão mapeados com códigos/textos Postgres (23505, 23503, violates foreign key constraint). O app default é MySQL (ER_DUP_ENTRY 1062, ER_ROW_IS_REFERENCED_2 1451, foreign key constraint fails). Delete em uso no MySQL pode virar 500 em vez de 409 se error.constraint não vier preenchido.


if (!authorization || typeof authorization !== 'string' || !authorization.startsWith('Bearer ')) {
return new ForbiddenError({ message: 'Token de autenticação obrigatório' })
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token ausente ou vazio retorna 403, papel diferente de 1|2 retorna 403, expirado ou inválido retorna 401. Os testes de POST/PUT/DELETE só enviam token de curador no caminho feliz; esses ramos novos não estão cobertos.


const ALLOWED_TIPOS_USUARIOS = new Set([1, 2])

export class RequireVegetacaoWriteAccess implements RequestHandler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RequireVegetacaoWriteAccess está no infinitivo inglês. Tipos novos devem usar 3ª pessoa do singular (RequiresVegetacaoWriteAccess) ou um verbo finito em português, sem misturar idiomas no nome.

}

const cause = error instanceof Error ? error : new Error(String(error))
return Either.left(new CollectionError({ message: cause.message, cause }))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O catch genérico devolve cause.message. Essa string chega no InternalServerError do controller e pode expor SQL no JSON de 500.


const ALLOWED_TIPOS_USUARIOS = new Set([1, 2])

export class ExigePermissaoEscritaVegetacao implements RequestHandler {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O arquivo RequerAcessoEscritaVegetacao.ts exporta ExigePermissaoEscritaVegetacao. O nome do arquivo deve coincidir com o tipo exportado: renomear para ExigePermissaoEscritaVegetacao.ts e ajustar o import em index.ts.

async handle(request: HttpRequest, next: NextHandler): Promise<HttpResponse | HttpError> {
const authorization = request.headers.Authorization ?? request.headers.authorization

if (!authorization || typeof authorization !== 'string' || !authorization.startsWith('Bearer ')) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Token ausente ou vazio retorna 403, papel diferente de 1|2 retorna 403, expirado ou inválido retorna 401. Os testes de escrita cobrem o happy path e JWT_SECRET ausente; esses ramos ainda não estão cobertos.

}
})

test('retorna 404 para id inexistente', async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ainda faltam PUT com nome vazio (400) e DELETE com vegetacaoId inválido (400) e inexistente (404). Este arquivo cobre sucesso, 404, id inválido e duplicidade; remove-vegetacoes.test.ts só cobre 204 e 409 em uso.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cadastrar, renomear e remover tipos de vegetação

2 participants